/*
 * Copyright (C) 2025 Tsingteng MicroSystem
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#include "nci_core.h"
#include "nci_types.h"
#include "nci_utils.h"
#include "nci_data.h"
#include "nfc_log_api.h"
#include "discover_int.h"

/**
 * @file nci_core.c
 * @brief NCI CORE group相关接口的实现
*/

#define NCI_DEFAULT_NFC_FEATURE 0x0000

/**
 * @brief 发送NCI CORE RESET命令
 *
 * @param[in] reset_type 复位类型
 * @param[out] p_ntf 用于保存复位结果的tNCI_CORE_RESET_NTF结构体指针,可以为NULL
 *
 * @return NCI_STATUS_OK 发送成功
 *         其他 发送失败
*/
tNCI_STATUS nci_core_reset(tNCI_RESET_TYPE reset_type, tNCI_CORE_RESET_NTF *p_ntf) {
    tNCI_STATUS ret = NCI_STATUS_EXT_FAILED;
    tNCI_BUF *cmd = alloc_nci_buf(NCI_CORE_RESET_CMD);
    tNCI_BUF *ntf = alloc_nci_buf(NCI_CORE_RESET_NTF);
    if (cmd == NULL || ntf == NULL) {
        ret = NCI_STATUS_EXT_ALLOC_FAILED;
        NFCLOG_E("alloc buf failed");
        goto cleanup;
    }

    UINT8_TO_BUF(cmd, reset_type);

    ret = nci_tp_send_nci_get_rsp_ntf(cmd, NULL, ntf, true, NCI_DEFAULT_WAIT_TIME);

    if (ret != NCI_STATUS_OK) {
        goto cleanup;
    }

    if (p_ntf) {
        uint8_t *p = ntf->data;
        STREAM_TO_UINT8(p_ntf->trigger, p);
        STREAM_TO_UINT8(p_ntf->configuration_status, p);
        STREAM_TO_UINT8(p_ntf->nci_version, p);
        STREAM_TO_UINT8(p_ntf->manufacturer_id, p);
        STREAM_TO_UINT8(p_ntf->manufacturer_specific_infomation_length, p);
        STREAM_TO_ARRAY(p_ntf->manufacturer_specific_infomation, p, p_ntf->manufacturer_specific_infomation_length);
    }

cleanup:
    free_nci_buf(cmd);
    free_nci_buf(ntf);
    return ret;
}

/**
 * @brief 发送NCI CORE INIT命令
 *
 * @param[out] p_resp 用于保存初始化结果的tNCI_INIT_RESP结构体指针,可以为NULL
 *
 * @return NCI_STATUS_OK 发送成功, 其他 发送失败
*/
tNCI_STATUS nci_core_init(tNCI_INIT_RESP *p_resp) {
    tNCI_STATUS ret = NCI_STATUS_EXT_FAILED;
    tNCI_BUF *cmd = alloc_nci_buf(NCI_CORE_INIT_CMD);
    tNCI_BUF *rsp = alloc_nci_buf(NCI_CORE_INIT_RSP);
    if (cmd == NULL || rsp == NULL) {
        ret = NCI_STATUS_EXT_ALLOC_FAILED;
        goto cleanup;
    }

    UINT16_TO_BUF_BE(cmd, NCI_DEFAULT_NFC_FEATURE);

    ret = nci_tp_send_nci_get_rsp_ntf(cmd, rsp, NULL, false, NCI_DEFAULT_WAIT_TIME);
    if (ret != NCI_STATUS_OK) {
        goto cleanup;
    }

    if (!p_resp) {
        // 不需要保存初始化结果，直接返回
        goto cleanup;
    }

    if (!p_resp) {
        // 不要保存初始化结果，直接返回
        goto cleanup;
    }

    uint8_t *p = &rsp->data[1]; // 跳过状态字节
    STREAM_TO_UINT32_BE(p_resp->nfcc_feature, p);
    STREAM_TO_UINT8(p_resp->max_logicl_conn, p);
    STREAM_TO_UINT16_LE(p_resp->max_routing_table_size, p);
    STREAM_TO_UINT8(p_resp->max_ctrl_packet_payload_size, p);
    STREAM_TO_UINT8(p_resp->max_hci_packet_payload_size, p);
    STREAM_TO_UINT8(p_resp->hci_credits_number, p);
    STREAM_TO_UINT16_LE(p_resp->max_nfcv_rf_frame_size, p);
    // 剩下的是支持的RF接口，暂时没有用处，不解析

cleanup:
    free_nci_buf(cmd);
    free_nci_buf(rsp);
    return ret;
}

/**
 * @brief 发送NCI CORE SET_COFNIG命令
 *
 * @param regs 需要设置的寄存器数组
 * @param len 寄存器数组长度
 *
 * @return 发送成功返回NCI_STATUS_OK, 其他 发送失败
*/
tNCI_STATUS nci_core_set_config(tNCI_REG *regs, uint8_t len) {
    tNCI_BUF *cmd = alloc_nci_buf(NCI_CORE_SET_CONFIG_CMD);
    if (cmd == NULL) {
        return NCI_STATUS_EXT_ALLOC_FAILED;
    }

    UINT8_TO_BUF(cmd, len);
    for (size_t i = 0; i < len; i++) {
        tNCI_REG reg = regs[i];
        if (reg.id > NCI_MAX_STD_REG_ID) {
            UINT16_TO_BUF_BE(cmd, reg.id);
        } else {
            UINT8_TO_BUF(cmd, reg.id);
        }
        UINT8_TO_BUF(cmd, reg.len);
        ARRAY_TO_BUF(cmd, reg.value, reg.len);
    }

    tNCI_STATUS ret = nci_tp_send_nci(cmd);

    free_nci_buf(cmd);
    return ret;
}

/**
 * @brief 发送NCI CORE GET_CONFIG命令
 *
 * @param[in] reg_ids 需要获取的寄存器ID数组
 * @param[in] len 寄存器ID数组长度
 * @param[out] regs 用于保存结果的寄存器数组
 *
 * @return 发送成功返回NCI_STATUS_OK, 其他 发送失败
*/
tNCI_STATUS nci_core_get_config(tNCI_REG_ID *reg_ids, uint8_t len, tNCI_REG *regs) {
    tNCI_BUF *cmd = alloc_nci_buf(NCI_CORE_GET_CONFIG_CMD);
    tNCI_BUF *rsp = alloc_nci_buf(NCI_CORE_GET_CONFIG_RSP);
    if (cmd == NULL || rsp == NULL) {
        free_nci_buf(cmd);
        free_nci_buf(rsp);
        return NCI_STATUS_EXT_ALLOC_FAILED;
    }

    UINT8_TO_BUF(cmd, len);
    for (size_t i = 0; i < len; i++) {
        tNCI_REG_ID reg_id = reg_ids[i];
        if (reg_id <= 0xFF) {
            UINT8_TO_BUF(cmd, reg_id);
        } else {
            UINT16_TO_BUF_BE(cmd, reg_id);
        }
    }

    tNCI_STATUS ret = nci_tp_send_nci_get_rsp_ntf(cmd, rsp, NULL, false, NCI_DEFAULT_WAIT_TIME);

    uint8_t *p;
    uint8_t i, temp;

    if (ret != NCI_STATUS_OK) {
        goto cleanup;
    }

    p = rsp->data;
    p++; // skip status
    p++; // skip reg num

    for (i = 0; i < len; i++) {
        tNCI_REG *reg = &regs[i];
        STREAM_TO_UINT8(reg->id, p);
        if ((reg->id & 0xF0) == NCI_EXT_REG_PREFIX) {
            // external register AXXX
            STREAM_TO_UINT8(temp, p);
            reg->id = (reg->id << 8) | temp;
        }
        STREAM_TO_UINT8(reg->len, p);
        STREAM_TO_ARRAY(reg->value, p, reg->len);
    }

cleanup:
    free_nci_buf(cmd);
    free_nci_buf(rsp);
    return ret;
}

/**
 * @brief 发送NCI CORE_CONN_CREATE命令
 *
 * @param[in] type 连接的类型
 * @param[in] params 连接参数
 * @param[in] size 连接参数个数
 * @param[out] channel_info 如果创建通道成功，则通过此返回连接信息
 *
 * @return 发送成功返回NCI_STATUS_OK, 其他 发送失败
*/
tNCI_STATUS nci_core_conn_create(tNCI_DESTINATION_TYPE type, tNCI_DEST_SPEC_PARAM* params, uint8_t size, tNCI_DATA_CHANNEL_INFO *channel_info) {
    if (channel_info == NULL) {
        return NCI_STATUS_EXT_INVALID_PARAM;
    }
    tNCI_BUF *cmd = alloc_nci_buf(NCI_CORE_CONN_CREATE_CMD);
    tNCI_BUF *rsp = alloc_nci_buf(NCI_CORE_CONN_CREATE_RSP);
    if (cmd == NULL || rsp == NULL) {
        free_nci_buf(cmd);
        free_nci_buf(rsp);
        return NCI_STATUS_EXT_ALLOC_FAILED;
    }

    UINT8_TO_BUF(cmd, type);
    UINT8_TO_BUF(cmd, size);

    uint8_t *p;

    for (size_t i = 0; i < size; i++) {
        tNCI_DEST_SPEC_PARAM param = params[i];
        UINT8_TO_BUF(cmd, param.type);
        UINT8_TO_BUF(cmd, param.len);
        UINT16_TO_BUF_BE(cmd, param.value);
    }

    tNCI_STATUS ret = nci_tp_send_nci_get_rsp_ntf(cmd, rsp, NULL, false, NCI_DEFAULT_WAIT_TIME);

    if (ret != NCI_STATUS_OK) {
        goto cleanup;
    }

    p = rsp->data;
    p++; // skip status

    STREAM_TO_UINT8(channel_info->max_data_packet_payload_size, p);
    STREAM_TO_UINT8(channel_info->initial_num_credits, p);
    STREAM_TO_UINT8(channel_info->conn_id, p);

cleanup:
    free_nci_buf(cmd);
    free_nci_buf(rsp);
    return ret;
}

/**
 * @brief 发送NCI CORE_CONN_CLOSE命令
 *
 * @param conn_id 需要关闭的conn_id
 *
 * @return 发送成功返回NCI_STATUS_OK, 其他 发送失败
*/
tNCI_STATUS nci_core_conn_close(uint8_t conn_id) {
    tNCI_BUF *cmd = alloc_nci_buf(NCI_CORE_CONN_CLOSE_CMD);
    if (cmd == NULL) {
        return NCI_STATUS_EXT_ALLOC_FAILED;
    }

    UINT8_TO_BUF(cmd, conn_id);

    tNCI_STATUS ret = nci_tp_send_nci(cmd);

    free_nci_buf(cmd);
    return ret;
}

/**
 * @brief 设置电源子状态
 *
 * @param power_state 状态
 *
 * @return NCI_STATUS_OK 发送成功, 其他 发送失败
 */
tNCI_STATUS nci_core_set_power_sub_state(tNCI_POWER_SUB_STATE power_state) {
    tNCI_BUF *cmd = alloc_nci_buf_with_cap(NCI_CORE_SET_POWER_SUB_STATE_CMD, 1);
    if (cmd == NULL) {
        return NCI_STATUS_EXT_ALLOC_FAILED;
    }

    UINT8_TO_BUF(cmd, power_state);

    tNCI_STATUS ret = nci_tp_send_nci(cmd);

    free_nci_buf(cmd);
    return ret;
}

/**
 * @brief 处理NCI CORE_CONN_CREDITS通知
 *
 * @param data NTF的payload数据
 * @param data_len NTF的payload数据长度
*/
void nci_core_conn_credits(uint8_t *data, uint16_t data_len) {
    if (!data || data_len == 0) {
        NFCLOG_E("invalid data, len=%d", data_len);
        return;
    }
    uint8_t *p = data;
    uint8_t num_of_entries = 0;

    STREAM_TO_UINT8(num_of_entries, p);
    for (uint8_t i = 0; i < num_of_entries; i++) {
        uint8_t conn_id = 0;
        uint16_t credits = 0;
        STREAM_TO_UINT8(conn_id, p);
        STREAM_TO_UINT8(credits, p);

        nci_data_channel_notify_credit(conn_id, credits);
    }
}

/**
 * @brief 处理NCI CORE_GENERIC_ERROR通知
*/
static void nci_core_generic_error(uint8_t *data, uint16_t data_len) {
    if (!data || data_len == 0) {
        NFCLOG_E("invalid data");
        return;
    }
    tNCI_STATUS status = (tNCI_STATUS) data[0];
    on_rf_error(status);
}

/**
 * @brief 处理NCI CORE_INTERFACE_ERROR通知
*/
static void nci_core_interface_error(uint8_t *data, uint16_t data_len) {
    if (!data || data_len < 2) {
        NFCLOG_E("invalid data");
        return;
    }
    tNCI_STATUS status = (tNCI_STATUS) data[0];
    uint8_t conn_id = data[1];
    if (conn_id == NCI_DATA_CHANNEL_RF) {
        on_rf_error(status);
    } else {
        NFCLOG_E("drop interface error conn_id: %d", conn_id);
    }
}

/**
 * @brief 处理NCI CORE相关的通知事件
 *
 * @param oid 事件的OID类型
 * @param data 事件的payload数据
 * @param data_len payload数据的长度
*/
void nci_core_ntf_handle(uint8_t oid, uint8_t *data, uint16_t data_len) {
    switch (oid) {
        case NCI_CORE_CONN_CREDITS:
            nci_core_conn_credits(data, data_len);
            break;
        case NCI_CORE_GENERIC_ERROR:
            nci_core_generic_error(data, data_len);
            break;
        case NCI_CORE_INTERFACE_ERROR:
            nci_core_interface_error(data, data_len);
            break;
        default:
            break;
    }
}
